home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / sc6.1 / part03 < prev    next >
Encoding:
Internet Message Format  |  1989-03-20  |  55.4 KB

  1. Subject:  v18i047:  SC spreadsheet, version 6.1, Part03/04
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Robert Bond <sequent!rgb@uunet.uu.net>
  7. Posting-number: Volume 18, Issue 47
  8. Archive-name: sc6.1/part03
  9.  
  10. # This is a shell archive.  Remove anything before this line
  11. # then unpack it by saving it in a file and typing "sh file"
  12. # (Files unpacked will be owned by you and have default permissions).
  13. # This archive contains the following files:
  14. #    ./gram.y
  15. #    ./interp.c
  16. #    ./crypt.c
  17. #
  18. if `test ! -s ./gram.y`
  19. then
  20. echo "Extracting ./gram.y"
  21. cat > ./gram.y << '\SHAR\EOF\'
  22. /*    SC    A Spreadsheet Calculator
  23.  *        Command and expression parser
  24.  *
  25.  *        original by James Gosling, September 1982
  26.  *        modified by Mark Weiser and Bruce Israel,
  27.  *            University of Maryland
  28.  *
  29.  *         more mods Robert Bond 12/86
  30.  *
  31.  *        More mods by Alan Silverstein, 3/88, see list of changes.
  32.  *
  33.  *        $Revision: 6.1 $
  34.  */
  35.  
  36.  
  37.  
  38. %{
  39. #include <curses.h>
  40. #include "sc.h"
  41.  
  42. #define ENULL (struct enode *)0
  43.  
  44. char *strcpy();
  45. %}
  46.  
  47. %union {
  48.     int ival;
  49.     double fval;
  50.     struct ent_ptr ent;
  51.     struct enode *enode;
  52.     char *sval;
  53.     struct range_s rval;
  54. }
  55.  
  56. %type <ent> var
  57. %type <fval> num
  58. %type <rval> range
  59. %type <rval> var_or_range
  60. %type <sval> strarg
  61. %type <enode> e term expr_list
  62. %token <sval> STRING
  63. %token <ival> NUMBER
  64. %token <fval> FNUMBER
  65. %token <rval> RANGE
  66. %token <rval> VAR
  67. %token <sval> WORD
  68. %token <ival> COL
  69. %token S_FORMAT
  70. %token S_LABEL
  71. %token S_LEFTSTRING
  72. %token S_RIGHTSTRING
  73. %token S_GET
  74. %token S_PUT
  75. %token S_MERGE
  76. %token S_LET
  77. %token S_WRITE
  78. %token S_TBL
  79. %token S_COPY
  80. %token S_SHOW
  81. %token S_ERASE
  82. %token S_FILL
  83. %token S_GOTO
  84. %token S_DEFINE
  85. %token S_UNDEFINE
  86. %token S_VALUE
  87. %token S_MDIR
  88. %token S_HIDE
  89. %token S_SET
  90.  
  91. %token K_FIXED
  92. %token K_SUM
  93. %token K_PROD
  94. %token K_AVG
  95. %token K_STDDEV
  96. %token K_ACOS
  97. %token K_ASIN
  98. %token K_ATAN
  99. %token K_ATAN2
  100. %token K_CEIL
  101. %token K_COS
  102. %token K_EXP
  103. %token K_FABS
  104. %token K_FLOOR
  105. %token K_HYPOT
  106. %token K_LN
  107. %token K_LOG
  108. %token K_PI
  109. %token K_POW
  110. %token K_SIN
  111. %token K_SQRT
  112. %token K_TAN
  113. %token K_DTR
  114. %token K_RTD
  115. %token K_MAX
  116. %token K_MIN
  117. %token K_RND
  118.  
  119. %token K_PV
  120. %token K_FV
  121. %token K_PMT
  122.  
  123. %token K_HOUR
  124. %token K_MINUTE
  125. %token K_SECOND
  126. %token K_MONTH
  127. %token K_DAY
  128. %token K_YEAR
  129. %token K_NOW
  130. %token K_DATE
  131. %token K_FMT
  132. %token K_SUBSTR
  133. %token K_STON
  134. %token K_EQS
  135. %token K_EXT
  136. %token K_NVAL
  137. %token K_SVAL
  138. %token K_LOOKUP
  139. %token K_INDEX
  140. %token K_STINDEX
  141. %token K_AUTO
  142. %token K_AUTOCALC
  143. %token K_BYROWS
  144. %token K_BYCOLS
  145. %token K_BYGRAPH
  146. %token K_ITERATIONS
  147. %token K_NUMERIC
  148. %token K_PRESCALE
  149. %token K_EXTFUN
  150. %token K_CELLCUR
  151. %token K_TOPROW
  152. %token K_TBLSTYLE
  153. %token K_TBL
  154. %token K_LATEX
  155. %token K_TEX
  156.  
  157. %left '?' ':'
  158. %left '|'
  159. %left '&'
  160. %nonassoc '<' '=' '>' '!'
  161. %left '+' '-' '#'
  162. %left '*' '/' '%'
  163. %left '^'
  164.  
  165. %%
  166. command:    S_LET var_or_range '=' e
  167.                 { let($2.left.vp, $4); }
  168.     |    S_LABEL var_or_range '=' e
  169.                 { slet($2.left.vp, $4, 0); }
  170.     |    S_LEFTSTRING var_or_range '=' e
  171.                 { slet($2.left.vp, $4, -1); }
  172.     |    S_RIGHTSTRING var_or_range '=' e
  173.                 { slet($2.left.vp, $4, 1); }
  174.     |    S_FORMAT COL ':' COL NUMBER NUMBER
  175.                 { doformat($2,$4,$5,$6); }
  176.     |    S_FORMAT COL NUMBER NUMBER
  177.                 { doformat($2,$2,$3,$4); }
  178.     |    S_GET strarg    {  /* This tmp hack is because readfile
  179.                     * recurses back through yyparse. */
  180.                   char *tmp;
  181.                   tmp = $2;
  182.                   readfile (tmp, 1);
  183.                   xfree(tmp);
  184.                 }
  185.     |    S_MERGE strarg    {
  186.                   char *tmp;
  187.                   tmp = $2;
  188.                   readfile (tmp, 0);
  189.                   xfree(tmp);
  190.                 }
  191.     |    S_MDIR strarg    
  192.                 { if (mdir) xfree(mdir); mdir = $2; }
  193.     |       S_PUT strarg range
  194.                 { (void) writefile($2, ($3.left.vp)->row, 
  195.                  ($3.left.vp)->col, ($3.right.vp)->row,
  196.                  ($3.right.vp)->col);
  197.                  xfree($2); }
  198.     |    S_PUT strarg    
  199.                 { (void) writefile ($2, 0, 0, maxrow, maxcol);
  200.                  xfree($2); }
  201.     |       S_WRITE strarg range { (void) printfile($2, ($3.left.vp)->row, 
  202.              ($3.left.vp)->col, ($3.right.vp)->row,
  203.              ($3.right.vp)->col);
  204.              xfree($2); }
  205.     |    S_WRITE strarg    { (void) printfile ($2, 0, 0, maxrow, maxcol);
  206.              xfree($2); }
  207.     |       S_TBL strarg range { (void) tblprintfile($2, ($3.left.vp)->row, 
  208.              ($3.left.vp)->col, ($3.right.vp)->row,
  209.              ($3.right.vp)->col);
  210.              xfree($2); }
  211.     |    S_TBL strarg    { (void)tblprintfile ($2, 0, 0, maxrow, maxcol);
  212.              xfree($2); }
  213.     |       S_SHOW COL ':' COL
  214.                     { showcol( $2, $4); }
  215.     |       S_SHOW NUMBER ':' NUMBER
  216.                     { showrow( $2, $4); }
  217.      |    S_HIDE COL
  218.                      { hide_col( $2 ); }
  219.      |    S_HIDE NUMBER
  220.                      { hide_row( $2 ); }
  221.     |    S_COPY range var_or_range 
  222.                     { copy($2.left.vp,$2.right.vp,
  223.                     $3.left.vp,$3.right.vp); }
  224.     |    S_ERASE       
  225.                     { eraser(lookat(showsr, showsc),
  226.                         lookat(currow, curcol)); }
  227.     |    S_ERASE var_or_range 
  228.                     { eraser($2.left.vp, $2.right.vp); }
  229.     |    S_VALUE       { valueize_area(showsr, showsc, currow, curcol);
  230.                  modflg++; }
  231.     |    S_VALUE var_or_range { valueize_area(($2.left.vp)->row,
  232.                 ($2.left.vp)->col,
  233.                 ($2.right.vp)->row,
  234.                 ($2.right.vp)->col); modflg++; }
  235.     |    S_FILL num num  { fill(lookat(showsr, showsc),
  236.                       lookat(currow, curcol), $2, $3); }
  237.     |    S_FILL var_or_range num num
  238.                  { fill($2.left.vp, $2.right.vp, $3, $4); }
  239.     |    S_GOTO var_or_range {moveto($2.left.vp->row, $2.left.vp->col);}
  240.     |       S_GOTO num          {num_search($2);}
  241.     |       S_GOTO STRING       {str_search($2);}
  242.     |    S_GOTO              {go_last();}
  243.     |    S_DEFINE strarg       { struct ent_ptr arg1, arg2;
  244.                     arg1.vp = lookat(showsr, showsc);
  245.                     arg1.vf = 0;
  246.                     arg2.vp = lookat(currow, curcol);
  247.                     arg2.vf = 0;
  248.                     add_range($2, arg1, arg2, 1); }
  249.  
  250.     |    S_DEFINE strarg range { add_range($2, $3.left, $3.right, 1); }
  251.     |    S_DEFINE strarg var   { add_range($2, $3, $3, 0); }
  252.     |    S_UNDEFINE var_or_range { del_range($2.left.vp, $2.right.vp); }
  253.      |    S_SET setlist
  254.     |    /* nothing */
  255.     |    error;
  256.  
  257. term:         var        { $$ = new_var('v', $1); }
  258.     |    K_FIXED term    { $$ = new ('f', ENULL, $2); }
  259.     |       '@' K_SUM '(' var_or_range ')' 
  260.                 { $$ = new_range(REDUCE | '+', $4); }
  261.     |       '@' K_PROD '(' var_or_range ')' 
  262.                 { $$ = new_range (REDUCE | '*', $4); }
  263.     |       '@' K_AVG '(' var_or_range ')' 
  264.                 { $$ = new_range (REDUCE | 'a', $4); }
  265.     |       '@' K_STDDEV '(' var_or_range ')' 
  266.                 { $$ = new_range (REDUCE | 's', $4); }
  267.     |       '@' K_MAX '(' var_or_range ')' 
  268.                 { $$ = new_range (REDUCE | MAX, $4); }
  269.     |    '@' K_MAX '(' e ',' expr_list ')'
  270.                 { $$ = new(LMAX, $6, $4); }
  271.     |       '@' K_MIN '(' var_or_range ')' 
  272.                 { $$ = new_range (REDUCE | MIN, $4); }
  273.     |    '@' K_MIN '(' e ',' expr_list ')'
  274.                 { $$ = new(LMIN, $6, $4); }
  275.     | '@' K_ACOS '(' e ')'
  276.             { $$ = new(ACOS, ENULL, $4); }
  277.     | '@' K_ASIN '(' e ')'     { $$ = new(ASIN, ENULL, $4); }
  278.     | '@' K_ATAN '(' e ')'     { $$ = new(ATAN, ENULL, $4); }
  279.     | '@' K_ATAN2 '(' e ',' e ')' { $$ = new(ATAN2, $4, $6); }
  280.     | '@' K_CEIL '(' e ')'     { $$ = new(CEIL, ENULL, $4); }
  281.     | '@' K_COS '(' e ')'     { $$ = new(COS, ENULL, $4); }
  282.     | '@' K_EXP '(' e ')'     { $$ = new(EXP, ENULL, $4); }
  283.     | '@' K_FABS '(' e ')'     { $$ = new(FABS, ENULL, $4); }
  284.     | '@' K_FLOOR '(' e ')'     { $$ = new(FLOOR, ENULL, $4); }
  285.     | '@' K_HYPOT '(' e ',' e ')'    { $$ = new(HYPOT, $4, $6); }
  286.     | '@' K_LN '(' e ')'     { $$ = new(LOG, ENULL, $4); }
  287.     | '@' K_LOG '(' e ')'     { $$ = new(LOG10, ENULL, $4); }
  288.     | '@' K_POW '(' e ',' e ')'    { $$ = new(POW, $4, $6); }
  289.     | '@' K_SIN '(' e ')'     { $$ = new(SIN, ENULL, $4); }
  290.     | '@' K_SQRT '(' e ')'     { $$ = new(SQRT, ENULL, $4); }
  291.     | '@' K_TAN '(' e ')'     { $$ = new(TAN, ENULL, $4); }
  292.     | '@' K_DTR '(' e ')'     { $$ = new(DTR, ENULL, $4); }
  293.     | '@' K_RTD '(' e ')'     { $$ = new(RTD, ENULL, $4); }
  294.     | '@' K_RND '(' e ')'     { $$ = new(RND, ENULL, $4); }
  295.  
  296.     | '@' K_PV  '(' e ',' e ',' e ')' { $$ = new(PV,  $4,new(':',$6,$8)); }
  297.      | '@' K_FV  '(' e ',' e ',' e ')' { $$ = new(FV,  $4,new(':',$6,$8)); }
  298.      | '@' K_PMT '(' e ',' e ',' e ')' { $$ = new(PMT, $4,new(':',$6,$8)); }
  299.  
  300.     | '@' K_HOUR '(' e ')'      { $$ = new(HOUR,ENULL, $4); }
  301.     | '@' K_MINUTE '(' e ')' { $$ = new(MINUTE,ENULL, $4); }
  302.     | '@' K_SECOND '(' e ')' { $$ = new(SECOND,ENULL, $4); }
  303.     | '@' K_MONTH '(' e ')'     { $$ = new(MONTH,ENULL,$4); }
  304.     | '@' K_DAY '(' e ')'    { $$ = new(DAY, ENULL, $4); }
  305.     | '@' K_YEAR '(' e ')'   { $$ = new(YEAR, ENULL, $4); }
  306.     | '@' K_NOW              { $$ = new(NOW, ENULL, ENULL);}
  307.     | '@' K_STON '(' e ')'   { $$ = new(STON, ENULL, $4); }
  308.     | '@' K_EQS '(' e ',' e ')' { $$ = new (EQS, $4, $6); }
  309.     | '@' K_DATE '(' e ')'     { $$ = new(DATE, ENULL, $4); }
  310.     | '@' K_FMT  '(' e ',' e ')' { $$ = new(FMT, $4, $6); }
  311.     | '@' K_INDEX  '(' e ',' var_or_range ')'
  312.          { $$ = new(INDEX, $4, new_range(REDUCE | INDEX, $6)); }
  313.     | '@' K_LOOKUP  '(' e ',' var_or_range ')'
  314.          { $$ = new(LOOKUP, $4, new_range(REDUCE | LOOKUP, $6)); }
  315.     | '@' K_STINDEX  '(' e ',' var_or_range ')'
  316.          { $$ = new(STINDEX, $4, new_range(REDUCE | STINDEX, $6)); }
  317.     | '@' K_EXT  '(' e ',' e ')' { $$ = new(EXT, $4, $6); }
  318.     | '@' K_NVAL '(' e ',' e ')' { $$ = new(NVAL, $4, $6); }
  319.     | '@' K_SVAL '(' e ',' e ')' { $$ = new(SVAL, $4, $6); }
  320.     | '@' K_SUBSTR '(' e ',' e ',' e ')'
  321.                  { $$ = new(SUBSTR, $4, new(',', $6, $8)); }
  322.     |    '(' e ')'     { $$ = $2; }
  323.     |    '+' term     { $$ = $2; }
  324.     |    '-' term     { $$ = new ('m', ENULL, $2); }
  325.     |    NUMBER         { $$ = new_const('k', (double) $1); }
  326.     |    FNUMBER         { $$ = new_const('k', $1); }
  327.     |    K_PI    { $$ = new_const('k', (double)3.14159265358979323846); }
  328.     |    STRING             { $$ = new_str($1); }
  329.     |    '~' term     { $$ = new ('~', ENULL, $2); }
  330.     |    '!' term     { $$ = new ('~', ENULL, $2); }
  331.     ;
  332.  
  333. e:        e '+' e        { $$ = new ('+', $1, $3); }
  334.     |    e '-' e        { $$ = new ('-', $1, $3); }
  335.     |    e '*' e        { $$ = new ('*', $1, $3); }
  336.     |    e '/' e        { $$ = new ('/', $1, $3); }
  337.     |    e '%' e        { $$ = new ('%', $1, $3); }
  338.     |    e '^' e        { $$ = new ('^', $1, $3); }
  339.     |    term
  340.     |    e '?' e ':' e    { $$ = new ('?', $1, new(':', $3, $5)); }
  341.     |    e '<' e        { $$ = new ('<', $1, $3); }
  342.     |    e '=' e        { $$ = new ('=', $1, $3); }
  343.     |    e '>' e        { $$ = new ('>', $1, $3); }
  344.     |    e '&' e        { $$ = new ('&', $1, $3); }
  345.     |    e '|' e        { $$ = new ('|', $1, $3); }
  346.     |    e '<' '=' e    { $$ = new ('~', ENULL, new ('>', $1, $4)); }
  347.     |    e '!' '=' e    { $$ = new ('~', ENULL, new ('=', $1, $4)); }
  348.     |    e '>' '=' e    { $$ = new ('~', ENULL, new ('<', $1, $4)); }
  349.     |    e '#' e        { $$ = new ('#', $1, $3); }
  350.     ;
  351.  
  352. expr_list:    e        { $$ = new(ELIST, ENULL, $1); }
  353.     |    expr_list ',' e    { $$ = new(ELIST, $1, $3); }
  354.     ;
  355.  
  356. range:        var ':' var    { $$.left = $1; $$.right = $3; }
  357.     |     RANGE        { $$ = $1; }
  358.     ;
  359.  
  360. var:        COL NUMBER    { $$.vp = lookat($2 , $1); $$.vf = 0;}
  361.     |    '$' COL NUMBER    { $$.vp = lookat($3 , $2);
  362.                     $$.vf = FIX_COL;}
  363.     |    COL '$' NUMBER    { $$.vp = lookat($3 , $1);
  364.                     $$.vf = FIX_ROW;}
  365.     |    '$' COL '$' NUMBER { $$.vp = lookat($4 , $2);
  366.                     $$.vf = FIX_ROW | FIX_COL;}
  367.     |    VAR        { $$ = $1.left; }
  368.     ;
  369.  
  370. var_or_range:    range        { $$ = $1; }
  371.     |    var        { $$.left = $1; $$.right = $1; }
  372.     ;
  373.  
  374. num:        NUMBER        { $$ = (double) $1; }
  375.     |    FNUMBER        { $$ = $1; }
  376.     |    '-' num        { $$ = -$2; }
  377.     |    '+' num        { $$ = $2; }
  378.     ;
  379.  
  380. strarg:        STRING        { $$ = $1; }
  381.     |    var        {
  382.                     char *s, *s1;
  383.                     s1 = $1.vp->label;
  384.                     if (!s1)
  385.                     s1 = "NULL_STRING";
  386.                     s = xmalloc((unsigned)strlen(s1)+1);
  387.                     (void) strcpy(s, s1);
  388.                     $$ = s;
  389.                 }
  390.       ;
  391.  
  392. setlist :    
  393.     |    setlist setitem
  394.     ;
  395.  
  396. setitem    :    K_AUTO        { setauto(1); }
  397.     |    K_AUTOCALC    { setauto(1); }
  398.     |    '~' K_AUTO    { setauto(0); }
  399.     |    '~' K_AUTOCALC    { setauto(0); }
  400.     |    '!' K_AUTO    { setauto(0); }
  401.     |    '!' K_AUTOCALC    { setauto(0); }
  402.     |    K_BYCOLS    { setorder(BYCOLS); }
  403.     |    K_BYROWS    { setorder(BYROWS); }
  404.     |    K_BYGRAPH    { setorder(BYGRAPH); }
  405.     |    K_NUMERIC    { numeric = 1; }
  406.     |    '!' K_NUMERIC    { numeric = 0; }
  407.     |    K_PRESCALE    { prescale = 0.01; }
  408.     |    '!' K_PRESCALE    { prescale = 1.0; }
  409.     |    K_EXTFUN    { extfunc = 1; }
  410.     |    '!' K_EXTFUN    { extfunc = 0; }
  411.     |    K_CELLCUR    { showcell = 1; }
  412.     |    '!' K_CELLCUR    { showcell = 0; }
  413.     |    K_TOPROW    { showtop = 1; }
  414.     |    '!' K_TOPROW    { showtop = 0; }
  415.     |    K_ITERATIONS '=' NUMBER    { setiterations($3); }
  416.     |    K_TBLSTYLE '=' NUMBER    { tbl_style = $3; }
  417.     |    K_TBLSTYLE '=' K_TBL    { tbl_style = TBL; }
  418.     |    K_TBLSTYLE '=' K_LATEX    { tbl_style = LATEX; }
  419.     |    K_TBLSTYLE '=' K_TEX    { tbl_style = TEX; }
  420.       ;
  421. \SHAR\EOF\
  422. else
  423.   echo "will not over write ./gram.y"
  424. fi
  425. if [ `wc -c ./gram.y | awk '{printf $1}'` -ne 11263 ]
  426. then
  427. echo `wc -c ./gram.y | awk '{print "Got " $1 ", Expected " 11263}'`
  428. fi
  429. if `test ! -s ./interp.c`
  430. then
  431. echo "Extracting ./interp.c"
  432. cat > ./interp.c << '\SHAR\EOF\'
  433. /*    SC    A Spreadsheet Calculator
  434.  *        Expression interpreter and assorted support routines.
  435.  *
  436.  *        original by James Gosling, September 1982
  437.  *        modified by Mark Weiser and Bruce Israel, 
  438.  *            University of Maryland
  439.  *
  440.  *              More mods Robert Bond, 12/86
  441.  *        More mods by Alan Silverstein, 3-4/88, see list of changes.
  442.  *        $Revision: 6.1 $
  443.  */
  444.  
  445. #include <math.h>
  446. #include <signal.h>
  447. #include <setjmp.h>
  448. #include <stdio.h>
  449.  
  450. extern int errno;        /* set by math functions */
  451. #ifdef BSD42
  452. #include <strings.h>
  453. #include <sys/time.h>
  454. #ifndef strchr
  455. #define strchr rindex
  456. #endif
  457. #else
  458. #include <time.h>
  459. #ifndef SYSIII
  460. #include <string.h>
  461. #endif
  462. #endif
  463.  
  464. #include <curses.h>
  465. #include "sc.h"
  466.  
  467. #if defined(BSD42) || defined(BSD43)
  468. char *re_comp();
  469. #endif
  470. #if defined(SYSV2) || defined(SYSV3)
  471. char *regcmp();
  472. char *regex();
  473. #endif
  474.  
  475. #ifdef SIGVOID
  476.     void quit();
  477. #else
  478.     int quit();
  479. #endif
  480.  
  481. /* Use this structure to save the the last 'g' command */
  482.  
  483. struct go_save {
  484.     int g_type;
  485.     double g_n;
  486.     char *g_s;
  487.     int  g_row;
  488.     int  g_col;
  489. } gs;
  490.  
  491. /* g_type can be: */
  492.  
  493. #define G_NONE 0            /* Starting value - must be 0*/
  494. #define G_NUM 1
  495. #define G_STR 2
  496. #define G_CELL 3
  497.  
  498. extern FILE *popen();
  499.  
  500. jmp_buf fpe_save;
  501. int    exprerr;       /* Set by eval() and seval() if expression errors */
  502. double  prescale = 1.0;    /* Prescale for constants in let() */
  503. int    extfunc  = 0;       /* Enable/disable external functions */
  504. int     loading = 0;       /* Set when readfile() is active */
  505. double fn1_eval();
  506. double fn2_eval();
  507.  
  508. #define PI (double)3.14159265358979323846
  509. #define dtr(x) ((x)*(PI/(double)180.0))
  510. #define rtd(x) ((x)*(180.0/(double)PI))
  511.  
  512. double finfunc(fun,v1,v2,v3)
  513. int fun;
  514. double v1,v2,v3;
  515. {
  516.      double answer,p;
  517.  
  518.      p = fn2_eval(pow, 1 + v2, v3);
  519.  
  520.      switch(fun)
  521.      {
  522.      case PV:
  523.          answer = v1 * (1 - 1/p) / v2;
  524.          break;
  525.      case FV:
  526.          answer = v1 * (p - 1) / v2;
  527.          break;
  528.      case PMT:
  529.          answer = v1 * v2 / (1 - 1/p);
  530.          break;
  531.     }
  532.     return(answer);
  533. }
  534.  
  535. char *
  536. dostindex( val, minr, minc, maxr, maxc)
  537. double val;
  538. int minr, minc, maxr, maxc;
  539. {
  540.     register r,c;
  541.     register struct ent *p;
  542.     char *pr;
  543.     int x;
  544.  
  545.     x = (int) val;
  546.     r = minr; c = minc;
  547.     p = 0;
  548.     if ( minr == maxr ) { /* look along the row */
  549.     c = minc + x - 1;
  550.     if (c <= maxc && c >=minc)
  551.         p = tbl[r][c];
  552.     } else if ( minc == maxc ) { /* look down the column */
  553.     r = minr + x - 1;
  554.     if (r <= maxr && r >=minr)
  555.         p = tbl[r][c];
  556.     } else {
  557.     error ("range specified to @stindex");
  558.     return(0);
  559.     }
  560.     if (p && p->label) {
  561.     pr = xmalloc((unsigned)(strlen(p->label)+1));
  562.     (void)strcpy(pr, p->label);
  563.     return (pr);
  564.      } else
  565.     return(0);
  566. }
  567.  
  568. double
  569. doindex( val, minr, minc, maxr, maxc)
  570. double val;
  571. int minr, minc, maxr, maxc;
  572. {
  573.     double v;
  574.     register r,c;
  575.     register struct ent *p;
  576.     int x;
  577.  
  578.     x = (int) val;
  579.     v = 0;
  580.     r = minr; c = minc;
  581.     if ( minr == maxr ) { /* look along the row */
  582.     c = minc + x - 1;
  583.     if (c <= maxc && c >=minc 
  584.         && (p = tbl[r][c] ) && p->flags&is_valid )
  585.                     return p->v;
  586.     }
  587.     else if ( minc == maxc ){ /* look down the column */
  588.     r = minr + x - 1;
  589.     if (r <= maxr && r >=minr 
  590.         && (p = tbl[r][c] ) && p->flags&is_valid )
  591.                     return p->v;
  592.     }
  593.     else error(" range specified to @index");
  594.     return v;
  595. }
  596.  
  597. double
  598. dolookupn( val, minr, minc, maxr, maxc)
  599. double val;
  600. int minr, minc, maxr, maxc;
  601. {
  602.     double v;
  603.     register r,c;
  604.     register struct ent *p;
  605.  
  606.     v = 0;
  607.     r = minr; c = minc;
  608.     if ( minr == maxr ) { /* look along the row */
  609.     for ( c = minc; c <= maxc; c++) {
  610.         if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
  611.             if(p->v <= val) {
  612.                 p = tbl[r+1][c];
  613.                 if ( p && p->flags&is_valid)
  614.                     v = p->v;
  615.                 }
  616.             else return v;
  617.             }
  618.         }
  619.     }
  620.     else if ( minc == maxc ){ /* look down the column */
  621.     for ( r = minr; r <= maxr; r++) {
  622.         if ( (p = tbl[r][c] ) && p->flags&is_valid ) {
  623.             if(p->v <= val) {
  624.                 p = tbl[r][c+1];
  625.                 if ( p && p->flags&is_valid)
  626.                     v = p->v;
  627.                 }
  628.             else return v;
  629.             }
  630.         }
  631.     }
  632.     else error(" range specified to @lookup");
  633.     return v;
  634. }
  635.  
  636. double
  637. dolookups(s, minr, minc, maxr, maxc)
  638. char *s;
  639. int minr, minc, maxr, maxc;
  640. {
  641.     double v;
  642.     register r,c;
  643.     register struct ent *p;
  644.  
  645.     v = 0;
  646.     r = minr; c = minc;
  647.     if ( minr == maxr ) { /* look along the row */
  648.     for ( c = minc; c <= maxc; c++) {
  649.         if ( (p = tbl[r][c] ) && p->label) {
  650.         if(strcmp(s,p->label) == 0) {
  651.             p = tbl[r+1][c];
  652.             xfree(s);
  653.             if ( p && p->flags & is_valid)
  654.             return(p->v);
  655.         }
  656.         }
  657.     }
  658.     } else if ( minc == maxc ) { /* look down the column */
  659.     for ( r = minr; r <= maxr; r++) {
  660.         if ( (p = tbl[r][c] ) && p->label) {
  661.         if(strcmp(s,p->label) == 0) {
  662.             p = tbl[r][c+1];
  663.             xfree(s);
  664.             if ( p && p->flags & is_valid)
  665.             return(p->v);
  666.         }
  667.         }
  668.     }
  669.     } else error(" range specified to @lookup");
  670.     xfree(s);
  671.     return v;
  672. }
  673.  
  674. double
  675. dosum(minr, minc, maxr, maxc)
  676. int minr, minc, maxr, maxc;
  677. {
  678.     double v;
  679.     register r,c;
  680.     register struct ent *p;
  681.  
  682.     v = 0;
  683.     for (r = minr; r<=maxr; r++)
  684.     for (c = minc; c<=maxc; c++)
  685.         if ((p = tbl[r][c]) && p->flags&is_valid)
  686.         v += p->v;
  687.     return v;
  688. }
  689.  
  690. double
  691. doprod(minr, minc, maxr, maxc)
  692. int minr, minc, maxr, maxc;
  693. {
  694.     double v;
  695.     register r,c;
  696.     register struct ent *p;
  697.  
  698.     v = 1;
  699.     for (r = minr; r<=maxr; r++)
  700.     for (c = minc; c<=maxc; c++)
  701.         if ((p = tbl[r][c]) && p->flags&is_valid)
  702.         v *= p->v;
  703.     return v;
  704. }
  705.  
  706. double
  707. doavg(minr, minc, maxr, maxc)
  708. int minr, minc, maxr, maxc;
  709. {
  710.     double v;
  711.     register r,c,count;
  712.     register struct ent *p;
  713.  
  714.     v = 0;
  715.     count = 0;
  716.     for (r = minr; r<=maxr; r++)
  717.     for (c = minc; c<=maxc; c++)
  718.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  719.         v += p->v;
  720.         count++;
  721.         }
  722.  
  723.     if (count == 0) 
  724.     return ((double) 0);
  725.  
  726.     return (v / (double)count);
  727. }
  728.  
  729. double
  730. dostddev(minr, minc, maxr, maxc)
  731. int minr, minc, maxr, maxc;
  732. {
  733.     double lp, rp, v, nd;
  734.     register r,c,n;
  735.     register struct ent *p;
  736.  
  737.     n = 0;
  738.     lp = 0;
  739.     rp = 0;
  740.     for (r = minr; r<=maxr; r++)
  741.     for (c = minc; c<=maxc; c++)
  742.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  743.         v = p->v;
  744.         lp += v*v;
  745.         rp += v;
  746.         n++;
  747.         }
  748.  
  749.     if ((n == 0) || (n == 1)) 
  750.     return ((double) 0);
  751.     nd = (double)n;
  752.     return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
  753. }
  754.  
  755. double
  756. domax(minr, minc, maxr, maxc)
  757. int minr, minc, maxr, maxc;
  758. {
  759.     double v;
  760.     register r,c,count;
  761.     register struct ent *p;
  762.  
  763.     count = 0;
  764.     for (r = minr; r<=maxr; r++)
  765.     for (c = minc; c<=maxc; c++)
  766.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  767.         if (!count) {
  768.             v = p->v;
  769.             count++;
  770.         } else if (p->v > v)
  771.             v = p->v;
  772.         }
  773.  
  774.     if (count == 0) 
  775.     return ((double) 0);
  776.  
  777.     return (v);
  778. }
  779.  
  780. double
  781. domin(minr, minc, maxr, maxc)
  782. int minr, minc, maxr, maxc;
  783. {
  784.     double v;
  785.     register r,c,count;
  786.     register struct ent *p;
  787.  
  788.     count = 0;
  789.     for (r = minr; r<=maxr; r++)
  790.     for (c = minc; c<=maxc; c++)
  791.         if ((p = tbl[r][c]) && p->flags&is_valid) {
  792.         if (!count) {
  793.             v = p->v;
  794.             count++;
  795.         } else if (p->v < v)
  796.             v = p->v;
  797.         }
  798.  
  799.     if (count == 0) 
  800.     return ((double) 0);
  801.  
  802.     return (v);
  803. }
  804.  
  805. double
  806. dotime(which, when)
  807. int which;
  808. double when;
  809. {
  810.     long time();
  811.  
  812.     static long t_cache;
  813.     static struct tm *tp;
  814.     long tloc;
  815.  
  816.     if (which == NOW) 
  817.         return (double)time((long *)0);
  818.  
  819.     tloc = (long)when;
  820.  
  821.     if (tloc != t_cache) {
  822.         tp = localtime(&tloc);
  823.         tp->tm_mon += 1;
  824.         tp->tm_year += 1900;
  825.         t_cache = tloc;
  826.     }
  827.  
  828.     switch (which) {
  829.         case HOUR: return((double)(tp->tm_hour));
  830.         case MINUTE: return((double)(tp->tm_min));
  831.         case SECOND: return((double)(tp->tm_sec));
  832.         case MONTH: return((double)(tp->tm_mon));
  833.         case DAY: return((double)(tp->tm_mday));
  834.         case YEAR: return((double)(tp->tm_year));
  835.     }
  836.     /* Safety net */
  837.     return (0.0);
  838. }
  839.  
  840. double
  841. doston(s)
  842. char *s;
  843. {
  844.     char *strtof();
  845.     double v;
  846.  
  847.     if (!s)
  848.     return((double)0.0);
  849.  
  850.     (void)strtof(s, &v);
  851.     xfree(s);
  852.     return(v);
  853. }
  854.  
  855. double
  856. doeqs(s1, s2)
  857. char *s1, *s2;
  858. {
  859.     double v;
  860.  
  861.     if (!s1 && !s2)
  862.     return(1.0);
  863.  
  864.     if (!s1 || !s2)
  865.     v = 0.0;
  866.     else if (strcmp(s1, s2) == 0)
  867.     v = 1.0;
  868.     else
  869.     v = 0.0;
  870.  
  871.     if (s1)
  872.         xfree(s1);
  873.  
  874.     if (s2)
  875.         xfree(s2);
  876.  
  877.     return(v);
  878. }
  879.  
  880.  
  881. /*
  882.  * Given a string representing a column name and a value which is a column
  883.  * number, return a pointer to the selected cell's entry, if any, else 0.  Use
  884.  * only the integer part of the column number.  Always free the string.
  885.  */
  886.  
  887. struct ent *
  888. getent (colstr, rowdoub)
  889.     char *colstr;
  890.     double rowdoub;
  891. {
  892.     int collen;        /* length of string */
  893.     int row, col;    /* integer values   */
  894.     struct ent *ep = 0;    /* selected entry   */
  895.  
  896.     if (((row = (int) floor (rowdoub)) >= 0)
  897.      && (row < MAXROWS)                /* in range */
  898.      && ((collen = strlen (colstr)) <= 2)    /* not too long */
  899.      && ((col = atocol (colstr, collen)) >= 0)
  900.      && (col < MAXCOLS))            /* in range */
  901.     {
  902.     ep = tbl [row] [col];
  903.     }
  904.  
  905.     xfree (colstr);
  906.     return (ep);
  907. }
  908.  
  909.  
  910. /*
  911.  * Given a string representing a column name and a value which is a column
  912.  * number, return the selected cell's numeric value, if any.
  913.  */
  914.  
  915. double
  916. donval (colstr, rowdoub)
  917.     char *colstr;
  918.     double rowdoub;
  919. {
  920.     struct ent *ep;
  921.  
  922.     return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
  923.         (ep -> v) : 0);
  924. }
  925.  
  926.  
  927. /*
  928.  *    The list routines (e.g. dolmax) are called with an LMAX enode.
  929.  *    The left pointer is a chain of ELIST nodes, the right pointer
  930.  *    is a value.
  931.  */
  932. double
  933. dolmax(ep)
  934. struct enode *ep;
  935. {
  936.     register int count = 0;
  937.     register double maxval = 0; /* Assignment to shut up lint */
  938.     register struct enode *p;
  939.     register double v;
  940.  
  941.     for (p = ep; p; p = p->e.o.left) {
  942.         v = eval(p->e.o.right);
  943.         if (!count || v > maxval) {
  944.             maxval = v; count++;
  945.         }
  946.     }
  947.     if (count) return maxval;
  948.     else return 0.0;
  949. }
  950.  
  951. double
  952. dolmin(ep)
  953. struct enode *ep;
  954. {
  955.     register int count = 0;
  956.     register double minval = 0; /* Assignment to shut up lint */
  957.     register struct enode *p;
  958.     register double v;
  959.  
  960.     for (p = ep; p; p = p->e.o.left) {
  961.         v = eval(p->e.o.right);
  962.         if (!count || v < minval) {
  963.             minval = v; count++;
  964.         }
  965.     }
  966.     if (count) return minval;
  967.     else return 0.0;
  968. }
  969.  
  970. double 
  971. eval(e)
  972. register struct enode *e;
  973. {
  974.  
  975.     if (e==0) return 0;
  976.     switch (e->op) {
  977.     case '+':    return (eval(e->e.o.left) + eval(e->e.o.right));
  978.     case '-':    return (eval(e->e.o.left) - eval(e->e.o.right));
  979.     case '*':    return (eval(e->e.o.left) * eval(e->e.o.right));
  980.     case '/':         return (eval(e->e.o.left) / eval(e->e.o.right));
  981.     case '%':     {    double num, denom;
  982.             num = floor(eval(e->e.o.left));
  983.             denom = floor(eval (e->e.o.right));
  984.             return denom ? num - floor(num/denom)*denom : 0; }
  985.     case '^':    return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
  986.     case '<':    return (eval(e->e.o.left) < eval(e->e.o.right));
  987.     case '=':    return (eval(e->e.o.left) == eval(e->e.o.right));
  988.     case '>':    return (eval(e->e.o.left) > eval(e->e.o.right));
  989.     case '&':    return (eval(e->e.o.left) && eval(e->e.o.right));
  990.     case '|':    return (eval(e->e.o.left) || eval(e->e.o.right));
  991.     case '?':    return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
  992.                         : eval(e->e.o.right->e.o.right);
  993.     case 'm':    return (-eval(e->e.o.right));
  994.     case 'f':    return (eval(e->e.o.right));
  995.     case '~':    return (eval(e->e.o.right) == 0.0);
  996.     case 'k':    return (e->e.k);
  997.     case 'v':    return (e->e.v.vp->v);
  998.     case INDEX:
  999.     case LOOKUP:
  1000.             {    register r,c;
  1001.         register maxr, maxc;
  1002.         register minr, minc;
  1003.         maxr = e->e.o.right->e.r.right.vp -> row;
  1004.         maxc = e->e.o.right->e.r.right.vp -> col;
  1005.         minr = e->e.o.right->e.r.left.vp -> row;
  1006.         minc = e->e.o.right->e.r.left.vp -> col;
  1007.         if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1008.         if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1009.         switch(e->op){
  1010.         case LOOKUP:
  1011.         if (etype(e->e.o.left) == NUM)
  1012.                 return dolookupn(eval(e->e.o.left), minr, minc, maxr, maxc);
  1013.         else
  1014.                 return dolookups(seval(e->e.o.left),minr, minc, maxr, maxc);
  1015.         case INDEX:
  1016.             return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
  1017.         }
  1018.         }
  1019.     case REDUCE | '+':
  1020.      case REDUCE | '*':
  1021.      case REDUCE | 'a':
  1022.      case REDUCE | 's':
  1023.     case REDUCE | MAX:
  1024.     case REDUCE | MIN:
  1025.         {    register r,c;
  1026.         register maxr, maxc;
  1027.         register minr, minc;
  1028.         maxr = e->e.r.right.vp -> row;
  1029.         maxc = e->e.r.right.vp -> col;
  1030.         minr = e->e.r.left.vp -> row;
  1031.         minc = e->e.r.left.vp -> col;
  1032.         if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1033.         if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1034.             switch (e->op) {
  1035.                 case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
  1036.                  case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
  1037.                  case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
  1038.                  case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
  1039.                  case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
  1040.                  case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
  1041.         }
  1042.         }
  1043.     case ACOS:     return (fn1_eval( acos, eval(e->e.o.right)));
  1044.     case ASIN:     return (fn1_eval( asin, eval(e->e.o.right)));
  1045.     case ATAN:     return (fn1_eval( atan, eval(e->e.o.right)));
  1046.     case ATAN2:     return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
  1047.     case CEIL:     return (fn1_eval( ceil, eval(e->e.o.right)));
  1048.     case COS:     return (fn1_eval( cos, eval(e->e.o.right)));
  1049.     case EXP:     return (fn1_eval( exp, eval(e->e.o.right)));
  1050.     case FABS:     return (fn1_eval( fabs, eval(e->e.o.right)));
  1051.     case FLOOR:     return (fn1_eval( floor, eval(e->e.o.right)));
  1052.     case HYPOT:     return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
  1053.     case LOG:     return (fn1_eval( log, eval(e->e.o.right)));
  1054.     case LOG10:     return (fn1_eval( log10, eval(e->e.o.right)));
  1055.     case POW:     return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
  1056.     case SIN:     return (fn1_eval( sin, eval(e->e.o.right)));
  1057.     case SQRT:     return (fn1_eval( sqrt, eval(e->e.o.right)));
  1058.     case TAN:     return (fn1_eval( tan, eval(e->e.o.right)));
  1059.     case DTR:     return (dtr(eval(e->e.o.right)));
  1060.     case RTD:     return (rtd(eval(e->e.o.right)));
  1061.     case RND:     {
  1062.                 double temp;
  1063.                 temp = eval(e->e.o.right);
  1064.                 return(temp-floor(temp) < 0.5 ?
  1065.                          floor(temp) : ceil(temp));
  1066.              }
  1067.     case FV:
  1068.     case PV:
  1069.     case PMT:    return(finfunc(e->op,eval(e->e.o.left),
  1070.                    eval(e->e.o.right->e.o.left),
  1071.                       eval(e->e.o.right->e.o.right)));
  1072.     case HOUR:     return (dotime(HOUR, eval(e->e.o.right)));
  1073.     case MINUTE:     return (dotime(MINUTE, eval(e->e.o.right)));
  1074.     case SECOND:     return (dotime(SECOND, eval(e->e.o.right)));
  1075.     case MONTH:     return (dotime(MONTH, eval(e->e.o.right)));
  1076.     case DAY:     return (dotime(DAY, eval(e->e.o.right)));
  1077.     case YEAR:     return (dotime(YEAR, eval(e->e.o.right)));
  1078.     case NOW:     return (dotime(NOW, (double)0.0));
  1079.     case STON:     return (doston(seval(e->e.o.right)));
  1080.     case EQS:        return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
  1081.     case LMAX:     return dolmax(e);
  1082.     case LMIN:     return dolmin(e);
  1083.     case NVAL:       return (donval(seval(e->e.o.left),eval(e->e.o.right)));
  1084.     default:     error ("Illegal numeric expression");
  1085.              exprerr = 1;
  1086.              return((double)0.0);
  1087.     }
  1088. #ifdef sequent
  1089.     return((double)0.0);    /* Quiet a questionable compiler complaint */
  1090. #endif
  1091. }
  1092.  
  1093. #ifdef SIGVOID
  1094. void
  1095. #endif
  1096. eval_fpe() /* Trap for FPE errors in eval */
  1097. {
  1098.     longjmp(fpe_save, 1);
  1099. }
  1100.  
  1101. double fn1_eval(fn, arg)
  1102. double (*fn)();
  1103. double arg;
  1104. {
  1105.     double res;
  1106.     errno = 0;
  1107.     res = (*fn)(arg);
  1108.     if(errno)
  1109.       eval_fpe();
  1110.  
  1111.     return res;
  1112. }
  1113.  
  1114. double fn2_eval(fn, arg1, arg2)
  1115. double (*fn)();
  1116. double arg1, arg2;
  1117. {
  1118.     double res;
  1119.     errno = 0;
  1120.     res = (*fn)(arg1, arg2);
  1121.     if(errno) 
  1122.         eval_fpe();
  1123.  
  1124.     return res;
  1125. }
  1126.  
  1127. /* 
  1128.  * Rules for string functions:
  1129.  * Take string arguments which they xfree.
  1130.  * All returned strings are assumed to be xalloced.
  1131.  */
  1132.  
  1133. char *
  1134. docat(s1, s2)
  1135. register char *s1, *s2;
  1136. {
  1137.     register char *p;
  1138.     char *arg1, *arg2;
  1139.  
  1140.     if (!s1 && !s2)
  1141.     return(0);
  1142.     arg1 = s1 ? s1 : "";
  1143.     arg2 = s2 ? s2 : "";
  1144.     p = xmalloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
  1145.     (void) strcpy(p, arg1);
  1146.     (void) strcat(p, arg2);
  1147.     if (s1)
  1148.         xfree(s1);
  1149.     if (s2)
  1150.         xfree(s2);
  1151.     return(p);
  1152. }
  1153.  
  1154. char *
  1155. dodate(tloc)
  1156. long tloc;
  1157. {
  1158.     char *tp;
  1159.     char *p;
  1160.  
  1161.     tp = ctime(&tloc);
  1162.     tp[24] = 0;
  1163.     p = xmalloc((unsigned)25);
  1164.     (void) strcpy(p, tp);
  1165.     return(p);
  1166. }
  1167.  
  1168.  
  1169. char *
  1170. dofmt(fmtstr, v)
  1171. char *fmtstr;
  1172. double v;
  1173. {
  1174.     char buff[1024];
  1175.     char *p;
  1176.  
  1177.     if (!fmtstr)
  1178.     return(0);
  1179.     (void)sprintf(buff, fmtstr, v);
  1180.     p = xmalloc((unsigned)(strlen(buff)+1));
  1181.     (void) strcpy(p, buff);
  1182.     xfree(fmtstr);
  1183.     return(p);
  1184. }
  1185.  
  1186.  
  1187. /*
  1188.  * Given a command name and a value, run the command with the given value and
  1189.  * read and return its first output line (only) as an allocated string, always
  1190.  * a copy of prevstr, which is set appropriately first unless external
  1191.  * functions are disabled, in which case the previous value is used.  The
  1192.  * handling of prevstr and freeing of command is tricky.  Returning an
  1193.  * allocated string in all cases, even if null, insures cell expressions are
  1194.  * written to files, etc.
  1195.  */
  1196.  
  1197. #ifdef VMS
  1198. char *
  1199. doext(command, value)
  1200. char *command;
  1201. double value;
  1202. {
  1203.     error("Warning: External functions unavailable on VMS");
  1204.     if (command)
  1205.     xfree(command);
  1206.     return (strcpy (xmalloc((unsigned) 1), "\0"));
  1207. }
  1208.  
  1209. #else /* VMS */
  1210.  
  1211. char *
  1212. doext (command, value)
  1213. char   *command;
  1214. double value;
  1215. {
  1216.     static char *prevstr = 0;    /* previous result */
  1217.     char buff[1024];        /* command line/return, not permanently alloc */
  1218.  
  1219.     if (!prevstr) {
  1220.     prevstr = xmalloc((unsigned)1);
  1221.     *prevstr = 0;
  1222.     }
  1223.     if (!extfunc)    {
  1224.     error ("Warning: external functions disabled; using %s value",
  1225.         prevstr ? "previous" : "null");
  1226.  
  1227.     if (command) xfree (command);
  1228.     } else {
  1229.     if (prevstr) xfree (prevstr);        /* no longer needed */
  1230.     prevstr = 0;
  1231.  
  1232.     if ((! command) || (! *command)) {
  1233.         error ("Warning: external function given null command name");
  1234.         if (command) xfree (command);
  1235.     } else {
  1236.         FILE *pp;
  1237.  
  1238.         (void) sprintf (buff, "%s %g", command, value); /* build cmd line */
  1239.         xfree (command);
  1240.  
  1241.         error ("Running external function...");
  1242.         (void) refresh();
  1243.  
  1244.         if ((pp = popen (buff, "r")) == (FILE *) NULL)    /* run it */
  1245.         error ("Warning: running \"%s\" failed", buff);
  1246.         else {
  1247.         if (fgets (buff, 1024, pp) == NULL)    /* one line */
  1248.             error ("Warning: external function returned nothing");
  1249.         else {
  1250.             char *cp;
  1251.  
  1252.             error ("");                /* erase notice */
  1253.             buff[1023] = 0;
  1254.  
  1255.             if (cp = strchr (buff, '\n'))    /* contains newline */
  1256.             *cp = 0;            /* end string there */
  1257.  
  1258.             (void) strcpy (prevstr = 
  1259.              xmalloc ((unsigned) (strlen (buff) + 1)), buff);
  1260.              /* save alloc'd copy */
  1261.         }
  1262.         (void) pclose (pp);
  1263.  
  1264.         } /* else */
  1265.     } /* else */
  1266.     } /* else */
  1267.     return (strcpy (xmalloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
  1268. }
  1269.  
  1270. #endif /* VMS */
  1271.  
  1272.  
  1273. /*
  1274.  * Given a string representing a column name and a value which is a column
  1275.  * number, return the selected cell's string value, if any.  Even if none,
  1276.  * still allocate and return a null string so the cell has a label value so
  1277.  * the expression is saved in a file, etc.
  1278.  */
  1279.  
  1280. char *
  1281. dosval (colstr, rowdoub)
  1282.     char *colstr;
  1283.     double rowdoub;
  1284. {
  1285.     struct ent *ep;
  1286.     char *label;
  1287.  
  1288.     label = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
  1289.     return (strcpy (xmalloc ((unsigned) (strlen (label) + 1)), label));
  1290. }
  1291.  
  1292.  
  1293. /*
  1294.  * Substring:  Note that v1 and v2 are one-based to users, but zero-based
  1295.  * when calling this routine.
  1296.  */
  1297.  
  1298. char *
  1299. dosubstr(s, v1, v2)
  1300. char *s;
  1301. register int v1,v2;
  1302. {
  1303.     register char *s1, *s2;
  1304.     char *p;
  1305.  
  1306.     if (!s)
  1307.     return(0);
  1308.  
  1309.     if (v2 >= strlen (s))        /* past end */
  1310.     v2 =  strlen (s) - 1;        /* to end   */
  1311.  
  1312.     if (v1 < 0 || v1 > v2) {        /* out of range, return null string */
  1313.     xfree(s);
  1314.     p = xmalloc((unsigned)1);
  1315.     p[0] = 0;
  1316.     return(p);
  1317.     }
  1318.     s2 = p = xmalloc((unsigned)(v2-v1+2));
  1319.     s1 = &s[v1];
  1320.     for(; v1 <= v2; s1++, s2++, v1++)
  1321.     *s2 = *s1;
  1322.     *s2 = 0;
  1323.     xfree(s);
  1324.     return(p);
  1325. }
  1326.  
  1327. char *
  1328. seval(se)
  1329. register struct enode *se;
  1330. {
  1331.     register char *p;
  1332.  
  1333.     if (se==0) return 0;
  1334.     switch (se->op) {
  1335.     case O_SCONST: p = xmalloc((unsigned)(strlen(se->e.s)+1));
  1336.              (void) strcpy(p, se->e.s);
  1337.              return(p);
  1338.     case O_VAR:    {
  1339.             struct ent *ep;
  1340.             ep = se->e.v.vp;
  1341.  
  1342.             if (!ep->label)
  1343.                 return(0);
  1344.             p = xmalloc((unsigned)(strlen(ep->label)+1));
  1345.             (void) strcpy(p, ep->label);
  1346.             return(p);
  1347.              }
  1348.     case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
  1349.     case 'f':    return(seval(se->e.o.right));
  1350.     case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
  1351.                          : seval(se->e.o.right->e.o.right));
  1352.     case DATE:   return(dodate((long)(eval(se->e.o.right))));
  1353.     case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
  1354.      case STINDEX:
  1355.          {    register r,c;
  1356.          register maxr, maxc;
  1357.          register minr, minc;
  1358.          maxr = se->e.o.right->e.r.right.vp -> row;
  1359.          maxc = se->e.o.right->e.r.right.vp -> col;
  1360.          minr = se->e.o.right->e.r.left.vp -> row;
  1361.          minc = se->e.o.right->e.r.left.vp -> col;
  1362.          if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1363.          if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1364.              return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
  1365.         }
  1366.     case EXT:    return(doext(seval(se->e.o.left), eval(se->e.o.right)));
  1367.     case SVAL:   return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
  1368.     case SUBSTR: return(dosubstr(seval(se->e.o.left),
  1369.                 (int)eval(se->e.o.right->e.o.left) - 1,
  1370.                 (int)eval(se->e.o.right->e.o.right) - 1));
  1371.     default:
  1372.              error ("Illegal string expression");
  1373.              exprerr = 1;
  1374.              return(0);
  1375.     }
  1376. }
  1377.  
  1378. /*
  1379.  * The graph formed by cell expressions which use other cells's values is not
  1380.  * evaluated "bottom up".  The whole table is merely re-evaluated cell by cell,
  1381.  * top to bottom, left to right, in RealEvalAll().  Each cell's expression uses
  1382.  * constants in other cells.  However, RealEvalAll() notices when a cell gets a
  1383.  * new numeric or string value, and reports if this happens for any cell.
  1384.  * EvalAll() repeats calling RealEvalAll() until there are no changes or the
  1385.  * evaluation count expires.
  1386.  */
  1387.  
  1388. int propagation = 10;    /* max number of times to try calculation */
  1389.  
  1390. setiterations(i)
  1391.     int i;
  1392.     {
  1393.     if(i<1){
  1394.         error("iteration count must be at least 1");
  1395.         propagation = 1;
  1396.         }
  1397.     else propagation = i;
  1398.     }
  1399.  
  1400. EvalAll () {
  1401.       int lastcnt, repct = 0;
  1402.   
  1403.      while ((lastcnt = RealEvalAll()) && (repct++ <= propagation));
  1404.      if((propagation>1)&& (lastcnt >0 ))
  1405.          error("Still changing after %d iterations",propagation-1);
  1406. }
  1407.  
  1408. /*
  1409.  * Evaluate all cells which have expressions and alter their numeric or string
  1410.  * values.  Return the number of cells which changed.
  1411.  */
  1412.  
  1413. int 
  1414. RealEvalAll () {
  1415.     register int i,j;
  1416.     int chgct = 0;
  1417.     register struct ent *p;
  1418.  
  1419.     (void) signal(SIGFPE, eval_fpe);
  1420.     if(calc_order == BYROWS ) {
  1421.     for (i=0; i<=maxrow; i++)
  1422.       for (j=0; j<=maxcol; j++)
  1423.          if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
  1424.     }
  1425.     else if ( calc_order == BYCOLS ) {
  1426.     for (j=0; j<=maxcol; j++)
  1427.      for (i=0; i<=maxrow; i++)
  1428.          if ((p=tbl[i][j]) && p->expr) RealEvalOne(p,i,j, &chgct);
  1429.     }
  1430.     else error("Internal error calc_order");
  1431.  
  1432.     (void) signal(SIGFPE, quit);
  1433.     return(chgct);
  1434. }
  1435.  
  1436. RealEvalOne(p, i , j, chgct)
  1437. register struct ent *p;
  1438. int i, j, *chgct;
  1439. {
  1440.     if (p->flags & is_strexpr) {
  1441.         char *v;
  1442.         if (setjmp(fpe_save)) {
  1443.         error("Floating point exception %s", v_name( i, j));
  1444.         v = "";
  1445.         } else {
  1446.         v = seval(p->expr);
  1447.         }
  1448.         if (!v && !p->label) /* Everything's fine */
  1449.         return;
  1450.         if (!p->label || !v || strcmp(v, p->label) != 0) {
  1451.         (*chgct)++;
  1452.         p->flags |= is_changed;
  1453.         }
  1454.         if(p->label)
  1455.         xfree(p->label);
  1456.         p->label = v;
  1457.     } else {
  1458.         double v;
  1459.         if (setjmp(fpe_save)) {
  1460.         error("Floating point exception %s", v_name( i, j));
  1461.         v = 0.0;
  1462.         } else {
  1463.         v = eval (p->expr);
  1464.         }
  1465.         if (v != p->v) {
  1466.         p->v = v; (*chgct)++;
  1467.         p->flags |= is_changed|is_valid;
  1468.         }
  1469.     }
  1470. }
  1471.  
  1472. struct enode *
  1473. new(op, a1, a2)
  1474. struct enode *a1, *a2;
  1475. {
  1476.     register struct enode *p;
  1477.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1478.     p->op = op;
  1479.     p->e.o.left = a1;
  1480.     p->e.o.right = a2;
  1481.     return p;
  1482. }
  1483.  
  1484. struct enode *
  1485. new_var(op, a1)
  1486. struct ent_ptr a1;
  1487. {
  1488.     register struct enode *p;
  1489.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1490.     p->op = op;
  1491.     p->e.v = a1;
  1492.     return p;
  1493. }
  1494.  
  1495. struct enode *
  1496. new_range(op, a1)
  1497. struct range_s a1;
  1498. {
  1499.     register struct enode *p;
  1500.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1501.     p->op = op;
  1502.     p->e.r = a1;
  1503.     return p;
  1504. }
  1505.  
  1506. struct enode *
  1507. new_const(op, a1)
  1508. double a1;
  1509. {
  1510.     register struct enode *p;
  1511.     p = (struct enode *) xmalloc ((unsigned)sizeof (struct enode));
  1512.     p->op = op;
  1513.     p->e.k = a1;
  1514.     return p;
  1515. }
  1516.  
  1517. struct enode *
  1518. new_str(s)
  1519. char *s;
  1520. {
  1521.     register struct enode *p;
  1522.  
  1523.     p = (struct enode *) xmalloc ((unsigned)sizeof(struct enode));
  1524.     p->op = O_SCONST;
  1525.     p->e.s = s;
  1526.     return(p);
  1527. }
  1528.  
  1529. copy(dv1, dv2, v1, v2)
  1530. struct ent *dv1, *dv2, *v1, *v2;
  1531. {
  1532.     int minsr, minsc;
  1533.     int maxsr, maxsc;
  1534.     int mindr, mindc;
  1535.     int maxdr, maxdc;
  1536.     int vr, vc;
  1537.     int r, c;
  1538.  
  1539.     mindr = dv1->row;
  1540.     mindc = dv1->col;
  1541.     maxdr = dv2->row;
  1542.     maxdc = dv2->col;
  1543.     if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
  1544.     if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
  1545.     maxsr = v2->row;
  1546.     maxsc = v2->col;
  1547.     minsr = v1->row;
  1548.     minsc = v1->col;
  1549.     if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
  1550.     if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
  1551.     if (maxdr >= MAXROWS  || 
  1552.            maxdc >= MAXCOLS) {
  1553.     error ("The table can't be any bigger");
  1554.     return;
  1555.     }
  1556.     erase_area(mindr, mindc, maxdr, maxdc);
  1557.     if (minsr == maxsr && minsc == maxsc) {
  1558.     /* Source is a single cell */
  1559.     for(vr = mindr; vr <= maxdr; vr++)
  1560.         for (vc = mindc; vc <= maxdc; vc++)
  1561.         copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
  1562.     } else if (minsr == maxsr) {
  1563.     /* Source is a single row */
  1564.     for (vr = mindr; vr <= maxdr; vr++)
  1565.         copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
  1566.     } else if (minsc == maxsc) {
  1567.     /* Source is a single column */
  1568.     for (vc = mindc; vc <= maxdc; vc++)
  1569.         copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
  1570.     } else {
  1571.     /* Everything else */
  1572.     copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
  1573.     }
  1574.     sync_refs();
  1575. }
  1576.  
  1577. copyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
  1578. int vr, vc, minsr, minsc, maxsr, maxsc;
  1579. {
  1580.     register struct ent *p;
  1581.     register struct ent *n;
  1582.     register int sr, sc;
  1583.     register int dr, dc;
  1584.  
  1585.     for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
  1586.     for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
  1587.         n = lookat (dr, dc);
  1588.         (void) clearent(n);
  1589.         if (p = tbl[sr][sc])
  1590.         copyent( n, p, dr - sr, dc - sc);
  1591.     }
  1592. }
  1593.  
  1594. eraser(v1, v2)
  1595. struct ent *v1, *v2;
  1596. {
  1597.     FullUpdate++;
  1598.     flush_saved();
  1599.     erase_area(v1->row, v1->col, v2->row, v2->col);
  1600.     sync_refs();
  1601. }
  1602.  
  1603. /* Goto subroutines */
  1604.  
  1605. g_free()
  1606. {
  1607.     switch (gs.g_type) {
  1608.     case G_STR: xfree(gs.g_s); break;
  1609.     default: break;
  1610.     }
  1611.     gs.g_type = G_NONE;
  1612. }
  1613.  
  1614. go_last()
  1615. {
  1616.     switch (gs.g_type) {
  1617.     case G_NONE:
  1618.         error("Nothing to repeat"); break;
  1619.     case G_NUM:
  1620.         num_search(gs.g_n);
  1621.         break;
  1622.     case  G_CELL:
  1623.         moveto(gs.g_row, gs.g_col);
  1624.             break;
  1625.     case  G_STR: 
  1626.         gs.g_type = G_NONE;    /* Don't free the string */
  1627.                str_search(gs.g_s); 
  1628.            break;
  1629.  
  1630.     default: error("go_last: internal error");
  1631.     }
  1632. }
  1633.  
  1634. moveto(row, col)
  1635. int row, col;
  1636. {
  1637.     currow = row;
  1638.     curcol = col;
  1639.     g_free();
  1640.     gs.g_type = G_CELL;
  1641.     gs.g_row = currow;
  1642.     gs.g_col = curcol;
  1643. }
  1644.  
  1645. num_search(n)
  1646. double n;
  1647. {
  1648.     register struct ent *p;
  1649.     register int r,c;
  1650.  
  1651.     g_free();
  1652.     gs.g_type = G_NUM;
  1653.     gs.g_n = n;
  1654.  
  1655.     r = currow;
  1656.     c = curcol;
  1657.     do {
  1658.     if (c < maxcol)
  1659.         c++;
  1660.     else {
  1661.         if (r < maxrow) {
  1662.         while(++r < maxrow && row_hidden[r]) /* */;
  1663.         c = 0;
  1664.         } else {
  1665.         r = 0;
  1666.         c = 0;
  1667.         }
  1668.     }
  1669.     if (r == currow && c == curcol) {
  1670.         error("Number not found");
  1671.         return;
  1672.     }
  1673.     p = tbl[r][c];
  1674.     } while(col_hidden[c] || !p || p && (!(p->flags & is_valid) 
  1675.                                         || (p->flags&is_valid) && p->v != n));
  1676.     currow = r;
  1677.     curcol = c;
  1678. }
  1679.  
  1680.  
  1681. str_search(s)
  1682. char *s;
  1683. {
  1684.     register struct ent *p;
  1685.     register int r,c;
  1686.     char *tmp;
  1687.  
  1688. #if defined(BSD42) || defined(BSD43)
  1689.     if ((tmp = re_comp(s)) != (char *)0) {
  1690.     xfree(s);
  1691.     error(tmp);
  1692.     return;
  1693.     }
  1694. #endif
  1695. #if defined(SYSV2) || defined(SYSV3)
  1696.     if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
  1697.     xfree(s);
  1698.     error("Invalid search string");
  1699.     return;
  1700.     }
  1701. #endif
  1702.     g_free();
  1703.     gs.g_type = G_STR;
  1704.     gs.g_s = s;
  1705.     r = currow;
  1706.     c = curcol;
  1707.     do {
  1708.     if (c < maxcol)
  1709.         c++;
  1710.     else {
  1711.         if (r < maxrow) {
  1712.         while(++r < maxrow && row_hidden[r]) /* */;
  1713.         c = 0;
  1714.         } else {
  1715.         r = 0;
  1716.         c = 0;
  1717.         }
  1718.     }
  1719.     if (r == currow && c == curcol) {
  1720.         error("String not found");
  1721. #if defined(SYSV2) || defined(SYSV3)
  1722.         free(tmp);
  1723. #endif
  1724.         return;
  1725.     }
  1726.     p = tbl[r][c];
  1727.     } while(col_hidden[c] || !p || p && (!(p->label) 
  1728. #if defined(BSD42) || defined(BSD43)
  1729.                       || (re_exec(p->label) == 0)));
  1730. #else
  1731. #if defined(SYSV2) || defined(SYSV3)
  1732.                                        || (regex(tmp, p->label) == (char *)0)));
  1733. #else
  1734.                                        || (strcmp(s, p->label) != 0)));
  1735. #endif
  1736. #endif
  1737.     currow = r;
  1738.     curcol = c;
  1739. #if defined(SYSV2) || defined(SYSV3)
  1740.     free(tmp);
  1741. #endif
  1742. }
  1743.  
  1744. fill (v1, v2, start, inc)
  1745. struct ent *v1, *v2;
  1746. double start, inc;
  1747. {
  1748.     register r,c;
  1749.     register struct ent *n;
  1750.     int maxr, maxc;
  1751.     int minr, minc;
  1752.  
  1753.     maxr = v2->row;
  1754.     maxc = v2->col;
  1755.     minr = v1->row;
  1756.     minc = v1->col;
  1757.     if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1758.     if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1759.     if (maxr >= MAXROWS) maxr = MAXROWS-1;
  1760.     if (maxc >= MAXCOLS) maxc = MAXCOLS-1;
  1761.     if (minr < 0) minr = 0;
  1762.     if (minr < 0) minr = 0;
  1763.  
  1764.     FullUpdate++;
  1765.     if( calc_order == BYROWS ) {
  1766.     for (r = minr; r<=maxr; r++)
  1767.     for (c = minc; c<=maxc; c++) {
  1768.         n = lookat (r, c);
  1769.         (void) clearent(n);
  1770.         n->v = start;
  1771.         start += inc;
  1772.         n->flags |= (is_changed|is_valid);
  1773.     }
  1774.     }
  1775.     else if ( calc_order == BYCOLS ) {
  1776.     for (c = minc; c<=maxc; c++)
  1777.     for (r = minr; r<=maxr; r++) {
  1778.         n = lookat (r, c);
  1779.         (void) clearent(n);
  1780.         n->v = start;
  1781.         start += inc;
  1782.         n->flags |= (is_changed|is_valid);
  1783.     }
  1784.     }
  1785.     else error(" Internal error calc_order");
  1786. }
  1787.  
  1788. let (v, e)
  1789. struct ent *v;
  1790. struct enode *e;
  1791. {
  1792.     double val;
  1793.  
  1794.     exprerr = 0;
  1795.     (void) signal(SIGFPE, eval_fpe);
  1796.     if (setjmp(fpe_save)) {
  1797.     error ("Floating point exception in cell %s", v_name(v->row, v->col));
  1798.     val = 0.0;
  1799.     } else {
  1800.     val = eval(e);
  1801.     }
  1802.     (void) signal(SIGFPE, quit);
  1803.     if (exprerr) {
  1804.     efree(e);
  1805.     return;
  1806.     }
  1807.     if (constant(e)) {
  1808.     if (!loading)
  1809.         v->v = val * prescale;
  1810.     else
  1811.         v->v = val;
  1812.     if (!(v->flags & is_strexpr)) {
  1813.             efree (v->expr);
  1814.         v->expr = 0;
  1815.     }
  1816.     efree(e);
  1817.         v->flags |= (is_changed|is_valid);
  1818.         changed++;
  1819.         modflg++;
  1820.     return;
  1821.     }
  1822.     efree (v->expr);
  1823.     v->expr = e;
  1824.     v->flags |= (is_changed|is_valid);
  1825.     v->flags &= ~is_strexpr;
  1826.     changed++;
  1827.     modflg++;
  1828. }
  1829.  
  1830. slet (v, se, flushdir)
  1831. struct ent *v;
  1832. struct enode *se;
  1833. int flushdir;
  1834. {
  1835.     char *p;
  1836.  
  1837.     exprerr = 0;
  1838.     (void) signal(SIGFPE, eval_fpe);
  1839.     if (setjmp(fpe_save)) {
  1840.     error ("Floating point exception in cell %s", v_name(v->row, v->col));
  1841.     p = "";
  1842.     } else {
  1843.     p = seval(se);
  1844.     }
  1845.     (void) signal(SIGFPE, quit);
  1846.     if (exprerr) {
  1847.     efree(se);
  1848.     return;
  1849.     }
  1850.     if (constant(se)) {
  1851.     label(v, p, flushdir);
  1852.     if (p)
  1853.         xfree(p);
  1854.     efree(se);
  1855.     if (v->flags & is_strexpr) {
  1856.             efree (v->expr);
  1857.         v->expr = 0;
  1858.         v->flags &= ~is_strexpr;
  1859.     }
  1860.     return;
  1861.     }
  1862.     efree (v->expr);
  1863.     v->expr = se;
  1864.     v->flags |= (is_changed|is_strexpr);
  1865.     if (flushdir<0) v->flags |= is_leftflush;
  1866.     else v->flags &= ~is_leftflush;
  1867.     FullUpdate++;
  1868.     changed++;
  1869.     modflg++;
  1870. }
  1871.  
  1872. hide_row(arg)
  1873. int arg;
  1874. {
  1875.     if (arg < 0) {
  1876.     error("Invalid Range");
  1877.     return;
  1878.     }
  1879.     if (arg > MAXROWS-2) {
  1880.     error("You can't hide the last row");
  1881.     return;
  1882.     }
  1883.     FullUpdate++;
  1884.     row_hidden[arg] = 1;
  1885. }
  1886.  
  1887. hide_col(arg)
  1888. int arg;
  1889. {
  1890.     if (arg < 0) {
  1891.     error("Invalid Range");
  1892.     return;
  1893.     }
  1894.     if (arg > MAXCOLS-2) {
  1895.     error("You can't hide the last col");
  1896.     return;
  1897.     }
  1898.     FullUpdate++;
  1899.     col_hidden[arg] = 1;
  1900. }
  1901.  
  1902. clearent (v)
  1903. struct ent *v;
  1904. {
  1905.     if (!v)
  1906.     return;
  1907.     label(v,"",-1);
  1908.     v->v = 0;
  1909.     if (v->expr)
  1910.     efree(v->expr);
  1911.     v->expr = 0;
  1912.     v->flags |= (is_changed);
  1913.     v->flags &= ~(is_valid);
  1914.     changed++;
  1915.     modflg++;
  1916. }
  1917.  
  1918. /*
  1919.  * Say if an expression is a constant (return 1) or not.
  1920.  */
  1921.  
  1922. constant (e)
  1923.     register struct enode *e;
  1924. {
  1925.     return ((e == 0)
  1926.      || ((e -> op) == O_CONST)
  1927.      || ((e -> op) == O_SCONST)
  1928.      || (((e -> op) != O_VAR)
  1929.       && (((e -> op) & REDUCE) != REDUCE)
  1930.       && constant (e -> e.o.left)
  1931.       && constant (e -> e.o.right)
  1932.       && (e -> op != EXT)     /* functions look like constants but aren't */
  1933.       && (e -> op != NVAL)
  1934.       && (e -> op != SVAL)
  1935.       && (e -> op != NOW)));
  1936. }
  1937.  
  1938. efree (e)
  1939. register struct enode *e;
  1940. {
  1941.     if (e) {
  1942.     if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
  1943.         && (e->op & REDUCE) != REDUCE) {
  1944.         efree(e->e.o.left);
  1945.         efree(e->e.o.right);
  1946.     }
  1947.     if (e->op == O_SCONST && e->e.s)
  1948.         xfree(e->e.s);
  1949.     xfree ((char *)e);
  1950.     }
  1951. }
  1952.  
  1953. label (v, s, flushdir)
  1954. register struct ent *v;
  1955. register char *s;
  1956. {
  1957.     if (v) {
  1958.     if (flushdir==0 && v->flags&is_valid) {
  1959.         register struct ent *tv;
  1960.         if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
  1961.         v = tv, flushdir = 1;
  1962.         else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
  1963.         v = tv, flushdir = -1;
  1964.         else flushdir = -1;
  1965.     }
  1966.     if (v->label) xfree((char *)(v->label));
  1967.     if (s && s[0]) {
  1968.         v->label = xmalloc ((unsigned)(strlen(s)+1));
  1969.         (void) strcpy (v->label, s);
  1970.     } else
  1971.         v->label = 0;
  1972.     if (flushdir<0) v->flags |= is_leftflush;
  1973.     else v->flags &= ~is_leftflush;
  1974.     FullUpdate++;
  1975.     modflg++;
  1976.     }
  1977. }
  1978.  
  1979. decodev (v)
  1980. struct ent_ptr v; 
  1981. {
  1982.     register struct range *r;
  1983.  
  1984.     if (!v.vp) (void)sprintf (line+linelim,"VAR?");
  1985.     else if (r = find_range((char *)0, 0, v.vp, v.vp))
  1986.         (void)sprintf(line+linelim, "%s", r->r_name);
  1987.     else
  1988.         (void)sprintf (line+linelim, "%s%s%s%d",
  1989.             v.vf & FIX_COL ? "$" : "",
  1990.             coltoa(v.vp->col),
  1991.             v.vf & FIX_ROW ? "$" : "",
  1992.             v.vp->row);
  1993.     linelim += strlen (line+linelim);
  1994. }
  1995.  
  1996. char *
  1997. coltoa(col)
  1998. int col;
  1999. {
  2000.     static char rname[3];
  2001.     register char *p = rname;
  2002.  
  2003.     if (col > 25) {
  2004.     *p++ = col/26 + 'A' - 1;
  2005.     col %= 26;
  2006.     }
  2007.     *p++ = col+'A';
  2008.     *p = 0;
  2009.     return(rname);
  2010. }
  2011.  
  2012. /*
  2013.  *    To make list elements come out in the same order
  2014.  *    they were entered, we must do a depth-first eval
  2015.  *    of the ELIST tree
  2016.  */
  2017. static
  2018. decompile_list(p)
  2019. struct enode *p;
  2020. {
  2021.     if (!p) return;
  2022.     decompile_list(p->e.o.left);    /* depth first */
  2023.         decompile(p->e.o.right, 0);
  2024.     line[linelim++] = ',';
  2025. }
  2026.  
  2027. decompile(e, priority)
  2028. register struct enode *e; {
  2029.     register char *s;
  2030.     if (e) {
  2031.     int mypriority;
  2032.     switch (e->op) {
  2033.     default: mypriority = 99; break;
  2034.     case '?': mypriority = 1; break;
  2035.     case ':': mypriority = 2; break;
  2036.     case '|': mypriority = 3; break;
  2037.     case '&': mypriority = 4; break;
  2038.     case '<': case '=': case '>': mypriority = 6; break;
  2039.     case '+': case '-': case '#': mypriority = 8; break;
  2040.     case '*': case '/': case '%': mypriority = 10; break;
  2041.     case '^': mypriority = 12; break;
  2042.     }
  2043.     if (mypriority<priority) line[linelim++] = '(';
  2044.     switch (e->op) {
  2045.     case 'f':    for (s="fixed "; line[linelim++] = *s++;);
  2046.             linelim--;
  2047.             decompile (e->e.o.right, 30);
  2048.             break;
  2049.     case 'm':    line[linelim++] = '-';
  2050.             decompile (e->e.o.right, 30);
  2051.             break;
  2052.     case '~':    line[linelim++] = '~';
  2053.             decompile (e->e.o.right, 30);
  2054.             break;
  2055.     case 'v':    decodev (e->e.v);
  2056.             break;
  2057.     case 'k':    (void)sprintf (line+linelim,"%.15g",e->e.k);
  2058.             linelim += strlen (line+linelim);
  2059.             break;
  2060.     case '$':    (void)sprintf (line+linelim, "\"%s\"", e->e.s);
  2061.             linelim += strlen(line+linelim);
  2062.             break;
  2063.  
  2064.     case REDUCE | '+': range_arg( "@sum(", e); break;
  2065.     case REDUCE | '*': range_arg( "@prod(", e); break;
  2066.     case REDUCE | 'a': range_arg( "@avg(", e); break;
  2067.     case REDUCE | 's': range_arg( "@stddev(", e); break;
  2068.     case REDUCE | MAX: range_arg( "@max(", e); break;
  2069.     case REDUCE | MIN: range_arg( "@min(", e); break;
  2070.  
  2071.     case ACOS:    one_arg( "@acos(", e); break;
  2072.     case ASIN:    one_arg( "@asin(", e); break;
  2073.     case ATAN:    one_arg( "@atan(", e); break;
  2074.     case ATAN2:    two_arg( "@atan2(", e); break;
  2075.     case CEIL:    one_arg( "@ceil(", e); break;
  2076.     case COS:    one_arg( "@cos(", e); break;
  2077.     case EXP:    one_arg( "@exp(", e); break;
  2078.     case FABS:    one_arg( "@fabs(", e); break;
  2079.     case FLOOR:    one_arg( "@floor(", e); break;
  2080.     case HYPOT:    two_arg( "@hypot(", e); break;
  2081.     case LOG:    one_arg( "@ln(", e); break;
  2082.     case LOG10:    one_arg( "@log(", e); break;
  2083.     case POW:    two_arg( "@pow(", e); break;
  2084.     case SIN:    one_arg( "@sin(", e); break;
  2085.     case SQRT:    one_arg( "@sqrt(", e); break;
  2086.     case TAN:    one_arg( "@tan(", e); break;
  2087.     case DTR:    one_arg( "@dtr(", e); break;
  2088.     case RTD:    one_arg( "@rtd(", e); break;
  2089.     case RND:    one_arg( "@rnd(", e); break;
  2090.     case HOUR:    one_arg( "@hour(", e); break;
  2091.     case MINUTE:    one_arg( "@minute(", e); break;
  2092.     case SECOND:    one_arg( "@second(", e); break;
  2093.     case MONTH:    one_arg( "@month(", e); break;
  2094.     case DAY:    one_arg( "@day(", e); break;
  2095.     case YEAR:    one_arg( "@year(", e); break;
  2096.     case DATE:    one_arg( "@date(", e); break;
  2097.     case STON:    one_arg( "@ston(", e); break;
  2098.     case FMT:    two_arg( "@fmt(", e); break;
  2099.     case EQS:    two_arg( "@eqs(", e); break;
  2100.     case NOW:    for ( s = "@now"; line[linelim++] = *s++;);
  2101.             linelim--;
  2102.             break;
  2103.     case LMAX:    list_arg("@max(", e); break;
  2104.     case LMIN:     list_arg("@min(", e); break;
  2105.     case FV:    three_arg("@fv(", e); break;
  2106.     case PV:    three_arg("@pv(", e); break;
  2107.     case PMT:    three_arg("@pmt(", e); break;
  2108.     case NVAL:    two_arg("@nval(", e); break;
  2109.     case SVAL:    two_arg("@sval(", e); break;
  2110.     case EXT:    two_arg("@ext(", e); break;
  2111.     case SUBSTR:    three_arg("@substr(", e); break;
  2112.     case STINDEX:    index_arg("@stindex(", e); break;
  2113.     case INDEX:    index_arg("@index(", e); break;
  2114.     case LOOKUP:    index_arg("@lookup(", e); break;
  2115.  
  2116.     default:    decompile (e->e.o.left, mypriority);
  2117.             line[linelim++] = e->op;
  2118.             decompile (e->e.o.right, mypriority+1);
  2119.             break;
  2120.  
  2121.     }
  2122.     if (mypriority<priority) line[linelim++] = ')';
  2123.     } else line[linelim++] = '?';
  2124. }
  2125.  
  2126. index_arg(s, e)
  2127. char *s;
  2128. struct enode *e;
  2129. {
  2130.     for (; line[linelim++] = *s++;);
  2131.     linelim--;
  2132.     decompile( e-> e.o.left, 0 );
  2133.     range_arg(", ", e->e.o.right);
  2134. }
  2135.  
  2136. list_arg(s, e)
  2137. char *s;
  2138. struct enode *e;
  2139. {
  2140.     for (; line[linelim++] = *s++;);
  2141.     linelim--;
  2142.  
  2143.     decompile (e->e.o.right, 0);
  2144.     line[linelim++] = ',';
  2145.     decompile_list(e->e.o.left);
  2146.     line[linelim - 1] = ')';
  2147. }
  2148.  
  2149. one_arg(s, e)
  2150. char *s;
  2151. struct enode *e;
  2152. {
  2153.     for (; line[linelim++] = *s++;);
  2154.     linelim--;
  2155.     decompile (e->e.o.right, 0);
  2156.     line[linelim++] = ')';
  2157. }
  2158.  
  2159. two_arg(s,e)
  2160. char *s;
  2161. struct enode *e;
  2162. {
  2163.     for (; line[linelim++] = *s++;);
  2164.     linelim--;
  2165.     decompile (e->e.o.left, 0);
  2166.     line[linelim++] = ',';
  2167.     decompile (e->e.o.right, 0);
  2168.     line[linelim++] = ')';
  2169. }
  2170.  
  2171. three_arg(s,e)
  2172. char *s;
  2173. struct enode *e;
  2174. {
  2175.     for (; line[linelim++] = *s++;);
  2176.     linelim--;
  2177.     decompile (e->e.o.left, 0);
  2178.     line[linelim++] = ',';
  2179.     decompile (e->e.o.right->e.o.left, 0);
  2180.     line[linelim++] = ',';
  2181.     decompile (e->e.o.right->e.o.right, 0);
  2182.     line[linelim++] = ')';
  2183. }
  2184.  
  2185. range_arg(s,e)
  2186. char *s;
  2187. struct enode *e;
  2188. {
  2189.     struct range *r;
  2190.  
  2191.     for (; line[linelim++] = *s++;);
  2192.     linelim--;
  2193.     if (r = find_range((char *)0, 0, e->e.r.left.vp,
  2194.                  e->e.r.right.vp)) {
  2195.     (void)sprintf(line+linelim, "%s", r->r_name);
  2196.     linelim += strlen(line+linelim);
  2197.     } else {
  2198.     decodev (e->e.r.left);
  2199.     line[linelim++] = ':';
  2200.     decodev (e->e.r.right);
  2201.     }
  2202.     line[linelim++] = ')';
  2203. }
  2204.  
  2205. editv (row, col)
  2206. int row, col;
  2207. {
  2208.     register struct ent *p;
  2209.  
  2210.     p = lookat (row, col);
  2211.     (void)sprintf (line, "let %s = ", v_name(row, col));
  2212.     linelim = strlen(line);
  2213.     if (p->flags & is_strexpr || p->expr == 0) {
  2214.     (void)sprintf (line+linelim, "%.15g", p->v);
  2215.     linelim += strlen (line+linelim);
  2216.     } else {
  2217.         editexp(row,col);
  2218.     }
  2219. }
  2220.  
  2221. editexp(row,col)
  2222. int row, col;
  2223. {
  2224.     register struct ent *p;
  2225.  
  2226.     p = lookat (row, col);
  2227.     decompile (p->expr, 0);
  2228.     line[linelim] = 0;
  2229. }
  2230.  
  2231. edits (row, col)
  2232. int row, col;
  2233. {
  2234.     register struct ent *p;
  2235.  
  2236.     p = lookat (row, col);
  2237.     (void)sprintf (line, "%sstring %s = ",
  2238.             ((p->flags&is_leftflush) ? "left" : "right"),
  2239.             v_name(row, col));
  2240.     linelim = strlen(line);
  2241.     if (p->flags & is_strexpr && p->expr) {
  2242.     editexp(row, col);
  2243.     } else if (p->label) {
  2244.         (void)sprintf (line+linelim, "\"%s\"", p->label);
  2245.         linelim += strlen (line+linelim);
  2246.     } else {
  2247.         (void)sprintf (line+linelim, "\"");
  2248.         linelim += 1;
  2249.     }
  2250. }
  2251. \SHAR\EOF\
  2252. else
  2253.   echo "will not over write ./interp.c"
  2254. fi
  2255. if [ `wc -c ./interp.c | awk '{printf $1}'` -ne 40555 ]
  2256. then
  2257. echo `wc -c ./interp.c | awk '{print "Got " $1 ", Expected " 40555}'`
  2258. fi
  2259. if `test ! -s ./crypt.c`
  2260. then
  2261. echo "Extracting ./crypt.c"
  2262. cat > ./crypt.c << '\SHAR\EOF\'
  2263. /*
  2264.  * Encryption utilites
  2265.  * Bradley Williams    
  2266.  * {allegra,ihnp4,uiucdcs,ctvax}!convex!williams
  2267.  * $Revision: 6.1 $
  2268.  */
  2269.  
  2270. #include <stdio.h>
  2271. #include <curses.h>
  2272.  
  2273. #if defined(BSD42) || defined(BSD43)
  2274. #include <sys/file.h>
  2275. #else
  2276. #include <fcntl.h>
  2277. #endif
  2278.  
  2279. #include "sc.h"
  2280.  
  2281. char        *strcpy();
  2282.  
  2283. #ifdef SYSV3
  2284. void exit();
  2285. #endif
  2286.  
  2287. int         Crypt = 0;
  2288.  
  2289. creadfile (save, eraseflg)
  2290. char *save;
  2291. int  eraseflg;
  2292. {
  2293.     register FILE *f;
  2294.     int pipefd[2];
  2295.     int fildes;
  2296.     int pid;
  2297.  
  2298.     if (eraseflg && strcmp(save, curfile) && modcheck(" first")) return;
  2299.  
  2300.     fildes = open (save, O_RDONLY, 0);
  2301.     if (fildes < 0)
  2302.     {
  2303.     error ("Can't read file \"%s\"", save);
  2304.     return;
  2305.     }
  2306.  
  2307.     if (eraseflg) erasedb ();
  2308.  
  2309.     if (pipe(pipefd) < 0) {
  2310.     error("Can't make pipe to child");
  2311.     return;
  2312.     }
  2313.  
  2314.     deraw();
  2315.     if ((pid=fork()) == 0)              /* if child  */
  2316.     {
  2317.     (void) close (0);          /* close stdin */
  2318.     (void) close (1);          /* close stdout */
  2319.     (void) close (pipefd[0]);      /* close pipe input */
  2320.     (void) dup (fildes);          /* standard in from file */
  2321.     (void) dup (pipefd[1]);          /* connect to pipe */
  2322.     (void) fprintf (stderr, " ");
  2323.     (void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
  2324.     exit (-127);
  2325.     }
  2326.     else                  /* else parent */
  2327.     {
  2328.     (void) close (fildes);
  2329.     (void) close (pipefd[1]);      /* close pipe output */
  2330.     f = fdopen (pipefd[0], "r");
  2331.     if (f == 0)
  2332.     {
  2333.         (void) kill (pid, -9);
  2334.         error ("Can't fdopen file \"%s\"", save);
  2335.         (void) close (pipefd[0]);
  2336.         return;
  2337.     }
  2338.     }
  2339.  
  2340.     loading++;
  2341.     while (fgets(line,sizeof line,f)) {
  2342.     linelim = 0;
  2343.     if (line[0] != '#') (void) yyparse ();
  2344.     }
  2345.     --loading;
  2346.     (void) fclose (f);
  2347.     (void) close (pipefd[0]);
  2348.     while (pid != wait(&fildes)) /**/;
  2349.     goraw();
  2350.     linelim = -1;
  2351.     modflg++;
  2352.     if (eraseflg) {
  2353.     (void) strcpy (curfile, save);
  2354.     modflg = 0;
  2355.     }
  2356.     EvalAll();
  2357. }
  2358.  
  2359. cwritefile (fname, r0, c0, rn, cn)
  2360. char *fname;
  2361. int r0, c0, rn, cn;
  2362. {
  2363.     register FILE *f;
  2364.     int pipefd[2];
  2365.     int fildes;
  2366.     int pid;
  2367.     char save[1024];
  2368.     char *fn;
  2369.  
  2370.  
  2371.     if (*fname == 0) fname = &curfile[0];
  2372.  
  2373.     fn = fname;
  2374.     while (*fn && (*fn == ' '))  /* Skip leading blanks */
  2375.     fn++;
  2376.  
  2377.     if ( *fn == '|' ) {
  2378.     error ("Can't have encrypted pipe");
  2379.     return(-1);
  2380.     }
  2381.  
  2382.     (void) strcpy(save,fname);
  2383.  
  2384.     fildes = open (save, O_WRONLY|O_CREAT, 0600);
  2385.     if (fildes < 0)
  2386.     {
  2387.     error ("Can't create file \"%s\"", save);
  2388.     return(-1);
  2389.     }
  2390.  
  2391.     if (pipe (pipefd) < 0) {
  2392.     error ("Can't make pipe to child\n");
  2393.     return(-1);
  2394.     }
  2395.  
  2396.     deraw();
  2397.     if ((pid=fork()) == 0)              /* if child  */
  2398.     {
  2399.     (void) close (0);              /* close stdin */
  2400.     (void) close (1);              /* close stdout */
  2401.     (void) close (pipefd[1]);          /* close pipe output */
  2402.     (void) dup (pipefd[0]);              /* connect to pipe input */
  2403.     (void) dup (fildes);              /* standard out to file */
  2404.     (void) fprintf (stderr, " ");
  2405.     (void) execl ("/bin/sh", "sh", "-c", "crypt", 0);
  2406.     exit (-127);
  2407.     }
  2408.     else                  /* else parent */
  2409.     {
  2410.     (void) close (fildes);
  2411.     (void) close (pipefd[0]);          /* close pipe input */
  2412.     f = fdopen (pipefd[1], "w");
  2413.     if (f == 0)
  2414.     {
  2415.         (void) kill (pid, -9);
  2416.         error ("Can't fdopen file \"%s\"", save);
  2417.         (void) close (pipefd[1]);
  2418.         return(-1);
  2419.     }
  2420.     }
  2421.  
  2422.     write_fd(f, r0, c0, rn, cn);
  2423.  
  2424.     (void) fclose (f);
  2425.     (void) close (pipefd[1]);
  2426.     while (pid != wait(&fildes)) /**/;
  2427.     (void) strcpy(curfile,save);
  2428.  
  2429.     modflg = 0;
  2430.     error ("File \"%s\" written", curfile);
  2431.     goraw();
  2432.     return(0);
  2433. }
  2434.  
  2435. \SHAR\EOF\
  2436. else
  2437.   echo "will not over write ./crypt.c"
  2438. fi
  2439. if [ `wc -c ./crypt.c | awk '{printf $1}'` -ne 3437 ]
  2440. then
  2441. echo `wc -c ./crypt.c | awk '{print "Got " $1 ", Expected " 3437}'`
  2442. fi
  2443. echo "Finished archive 3 of 4"
  2444. # if you want to concatenate archives, remove anything after this line
  2445. exit
  2446.  
  2447.